﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using EnvDTE;
using System.Xml;
using System.IO;
using SPVisualDev.Services;
using SPVisualDev.VSAddin.Services;
using EnvDTE80;
using SPVisualDev.VSAddin.Dialogs;

namespace SPVisualDev.VSAddin
{
    public class SpecialProject : IDisposable
    {
        private Project m_project;
        private XmlDocument m_user_settings_xml = new XmlDocument();
        private MainServiceWrapper m_service_proxy;
        private ConnectionDetailsStruct m_remote_connection;
        private DTE2 m_dte;
        private string m_project_name;

        public SpecialProject(Project project, SpecialSolution specialSolution)
        {
            if (!Common.CheckIfSpecialProject(project))
                throw new Exception("Project is not a SPVisualDev special project.");

            m_project = project;
            m_dte = project.DTE as DTE2;
            m_project_name = project.UniqueName;

            this.SpecialSolution = specialSolution;

            LoadSettings();

            this.PushDown = new PushDownManager(this);
            this.PushDown.ReadSettings();

            m_remote_connection = Common.GetServiceConnection(this);
        }

        public void Dispose()
        {
            if (m_service_proxy != null)
            {
                m_service_proxy.Dispose();
            }
        }

        public SpecialSolution SpecialSolution
        {
            get;
            private set;
        }

        public Project Project
        {
            get 
            {
                try
                {
                    string name = m_project.FileName;
                }
                catch
                {
                    m_project = m_dte.Solution.Projects.Item(m_project_name);
                }

                return m_project; 
            }
        }

        public PushDownManager PushDown
        {
            get;
            private set;
        }

        public IMainService ServiceProxy
        {
            get
            {
                if (m_service_proxy == null)
                {
                    m_remote_connection = Common.GetServiceConnection(this);

                    m_service_proxy = new MainServiceWrapper(m_remote_connection);
                }

                return m_service_proxy.ServiceProxy;
            }
        }

        public void ReloadServiceProxy()
        {
            if (m_service_proxy != null)
            {
                m_service_proxy.Dispose();
                m_service_proxy = null;

            }

            m_remote_connection = Common.GetServiceConnection(this);
        }

        public List<DialogIncludedAssemblies.IncludeAssemblyStruct> GetIncludedAssemblies()
        {
            List<DialogIncludedAssemblies.IncludeAssemblyStruct> ret = new List<DialogIncludedAssemblies.IncludeAssemblyStruct>();

            string included_assemblies = Common.GetProjectGlobalConfigKey(m_project, "IncludedAssemblies");
            VSLangProj80.VSProject2 vsproj = (VSLangProj80.VSProject2)m_project.Object;

            string[] arr1 = included_assemblies.ToLower().Split(';');
            string[] arr2 = null;

            if (!string.IsNullOrEmpty(GetUserSettingsValue("IncludedReferencedAssemblies")))
            {
                arr2 = GetUserSettingsValue("IncludedReferencedAssemblies").ToLower().Split(';');
            }

            for (int i = 1; i <= vsproj.References.Count; i++)
            {
                VSLangProj.Reference r = vsproj.References.Item(i) as VSLangProj.Reference;
                DialogIncludedAssemblies.IncludeAssemblyStruct asm = new DialogIncludedAssemblies.IncludeAssemblyStruct();
                asm.Name = r.Name;

                if (r.Name.StartsWith("System.") ||
                    r.Name == "mscorlib" ||
                    r.Name == "Microsoft.SharePoint" ||
                    r.Name == "System" ||
                    r.Name.StartsWith("Microsoft.SharePoint."))
                    continue;

                if (Array.IndexOf(arr1, r.Name.ToLower()) != -1)
                {
                    asm.IncludeInWSP = true;
                }

                if (arr2 != null && Array.IndexOf(arr2, r.Name.ToLower()) != -1)
                {
                    asm.IncludeWhenBuilding = true;
                }

                ret.Add(asm);
            }

            return ret;
        }

        public string GetUserSettingsValue(string Key)
        {
            XmlNode xn = m_user_settings_xml.DocumentElement.SelectSingleNode(Key);
            if (xn != null)
                return xn.InnerText;
            else
                return null;
        }

        public void SetUserSettingsValue(string Key, string Value, bool WriteImmediately)
        {
            if (Value == null)
                Value = string.Empty;

            XmlNode xn = m_user_settings_xml.DocumentElement.SelectSingleNode(Key);
            if (xn != null)
                xn.InnerText = Value;
            else
            {
                XmlElement el = m_user_settings_xml.CreateElement(Key);
                el.InnerText = Value;
                m_user_settings_xml.DocumentElement.AppendChild(el);
            }

            if (WriteImmediately)
            {
                SaveSettings();
            }
        }

        public void LoadSettings()
        {
            if (m_project == null)
                throw new NullReferenceException("No project assigned.");


            string settings_file = m_project.Properties.Item("LocalPath").Value.ToString() + Common.C_SETTINGS_FILE;
            try
            {
                /*Added check for upgraded version of settings file*/
                XmlDocument xmldoc = new XmlDocument();

                if (!File.Exists(settings_file))
                {
                    settings_file = m_project.Properties.Item("LocalPath").Value.ToString() + Common.C_SETTINGS_FILE_V2;
                }

                if (!File.Exists(settings_file))
                {
                    xmldoc.LoadXml("<Settings></Settings>");
                    xmldoc.Save(settings_file);
                }
                else
                {
                    xmldoc.Load(settings_file);
                }

                m_user_settings_xml = xmldoc;
            }
            catch (Exception ex)
            {
                throw new Exception("Failed to create load settings file at " + settings_file + ". " + ex.Message);
            }
        }

        public void SaveSettings()
        {
            if (m_project == null)
                throw new NullReferenceException("No project assigned.");

            string settings_file = m_project.Properties.Item("LocalPath").Value.ToString() + Common.C_SETTINGS_FILE;
            try
            {
                /*Added check for upgraded version of settings file*/
                if (File.Exists(settings_file))
                {
                    m_user_settings_xml.Save(settings_file);
                }
                else
                {
                    settings_file = m_project.Properties.Item("LocalPath").Value.ToString() + Common.C_SETTINGS_FILE_V2;
                    m_user_settings_xml.Save(settings_file);
                }

            }
            catch (Exception ex)
            {
                throw new Exception("Failed to create load settings file at " + settings_file + ". " + ex.Message);
            }
        }

        public bool IsRemoteConfigFromSolution
        {
            get { return this.SpecialSolution.UseRemoteServer; }
        }

        public bool UseRemoteServer
        {
            get
            {
                if (!string.IsNullOrEmpty(this.RemoteConnection.Address) || this.SpecialSolution.UseRemoteServer)
                    return true;
                else
                    return false;
            }
        }

        public bool UseService
        {
            get
            {
                if (UseRemoteServer || this.RemoteConnection.Port != 0)
                    return true;
                else
                    return false;
            }
        }

        public ConnectionDetailsStruct RemoteConnection
        {
            get
            {
                return m_remote_connection;
            }
        }
    }
}
